package com.onec.service.gateway.filter;


import cn.hutool.core.util.CharsetUtil;
import cn.hutool.json.JSONUtil;
import com.onec.service.api.content.FilterContent;
import com.onec.service.api.dto.response.ResponseData;
import com.onec.service.gateway.service.system.BaseSourceService;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.reactive.HiddenHttpMethodFilter;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Map;


/**
 * 将返回的明文加密处理！
 *
 * @author onec
 */
@Component
public class ResponseEncryptFilter implements GlobalFilter, Ordered {
    private static final Logger log = LoggerFactory.getLogger(ResponseEncryptFilter.class);


    @Autowired
    private Map<String, BaseSourceService> serviceMap;

    @Override
    public int getOrder() {
        // -1 is response write filter, must be called before that
        return -2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        // get 请求返回报文不全：
        HttpHeaders httpHeaders = exchange.getRequest().getHeaders();

        String agentNo = httpHeaders.getFirst(FilterContent.AUTHORIZE_AGENT_NO);
        String source = httpHeaders.getFirst(FilterContent.AUTHORIZE_SOURCE);
        log.info("获取到的 :headers:{},{}", agentNo, source);
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (HttpMethod.POST.equals(exchange.getRequest().getMethod())) {
                    if (body instanceof Mono) {
                        Mono<? extends DataBuffer> mono = Mono.from(body);
                        body = mono.flux();
                    }
                    if (body instanceof Flux) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                        return super.writeWith(fluxBody.buffer().map(dataBuffer -> {
                            DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                            DataBuffer join = dataBufferFactory.join(dataBuffer);
                            byte[] content = new byte[join.readableByteCount()];
                            join.read(content);
                            DataBufferUtils.release(join);
                            String response = new String(content, CharsetUtil.CHARSET_UTF_8);
                            log.info(":请求返回明文：【{}】", response);
                            ResponseData responseData = ResponseData.success(response);
                            responseData.setAgentNo(agentNo);
                            //if (responseData.isSuccess()) {
                            responseData = serviceMap.get(source).encryptResponseData(responseData);
                            //}
                            log.info(":请求返回密文：【{}】", JSONUtil.toJsonStr(responseData));
                            String responseContent = JSONUtil.toJsonStr(responseData);
                            byte[] contentByte = responseContent.getBytes(StandardCharsets.UTF_8);
                            originalResponse.getHeaders().setContentLength(contentByte.length);
                            return bufferFactory.wrap(contentByte);
                        }));
                    }
                }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };
        // replace response with decorator
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    /**
     * @return
     */
    @Bean
    public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
        return new HiddenHttpMethodFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
                return chain.filter(exchange);
            }
        };
    }
}
